
#include <QFile>
#include <QFileInfo>
#include <QSettings>
#include <QRegExp>
#include <cmath>
#include "defaultagent.h"
#include "log.h"
#include "components/chan.h"
#include "components/board.h"
#include "captchafetchers/genericcaptchafetcher.h"
#include "tasks/taskrequest.h"
#include "tasks/taskboardrequest.h"
#include "tasks/taskthreadrequest.h"
#include "tasks/taskthumbnailrequest.h"
#include "tasks/taskattachmentrequest.h"

namespace Wishmaster
{
	static const char* PageProperty = "page";
	DefaultAgent::DefaultAgent(const QString& host) : ChanAgent(host),
		m_host(host), m_captchaFetcher(0)
	{
		m_pageformat = property("pageformat").toString();
	}

	void DefaultAgent::setTaskhub(Taskhub* taskhub)
	{
		m_taskhub = taskhub;
	}
	
	Taskhub* DefaultAgent::taskhub()
	{
		return m_taskhub;
	}

	void DefaultAgent::setRequestManager(Wishmaster2::Network::RequestManager* manager)
	{
		m_requestManager = manager;
	}

	Wishmaster2::Network::RequestManager* DefaultAgent::requestManager() const
	{
		return m_requestManager;
	}

	void DefaultAgent::setCaptchaFetcher(CaptchaFetcher* fetcher)
	{
		if(m_captchaFetcher)
			delete m_captchaFetcher;
		m_captchaFetcher = fetcher;
		if(m_captchaFetcher)
			connect(m_captchaFetcher, SIGNAL(captcha(ThreadId,QByteArray)), this, SLOT(slot_captchaFetcherResult(ThreadId,QByteArray)));
	}

	CaptchaFetcher* DefaultAgent::captchaFetcher() const
	{
		return m_captchaFetcher;
	}

	void DefaultAgent::getCaptcha(const ThreadId& threadId)
	{
		if(!captchaFetcher())
			return;
		captchaFetcher()->fetchCaptcha(threadId);
	}

	QString DefaultAgent::makeThreadLink(const ThreadId& threadId)
	{
		QString threadlink = property("threadlink").toString();
		if(threadlink.isEmpty())
		{
			return QString("%1res/%2.html").arg(threadId.boardId()).arg(threadId.threadStringId());
		}
		threadlink.replace("%BOARD%", threadId.boardId());
		threadlink.replace("%THREADID%", threadId.threadStringId());
		return threadlink;
	}

	void DefaultAgent::requestFavicon()
	{
		log(llDebug, "DefaultAgent::requestFavicon");
		Wishmaster2::Network::Url url("http://" + makeFullHostname(QString()).toStdString());
		TaskRequest* task = new TaskRequest(TaskRequest::rtOther, url, tr("Requesting favicon (1)"), requestManager());

		connect(task, SIGNAL(result(TaskRequest*,QByteArray,QString)), this, SLOT(slot_mainpage(TaskRequest*,QByteArray,QString)));
		TaskPtr taskptr = TaskPtr(task);
		m_taskhub->queueTask(taskptr);
	}

	void DefaultAgent::requestThread(const ThreadId& threadId, const PostId& lastPostId)
	{
		Q_UNUSED(lastPostId);

		QString reqlink = makeThreadLink(threadId);
		Wishmaster2::Network::Url url((QString("http://") + makeFullHostname(threadId.boardId()) + reqlink).toStdString());
		log(llDebug, "requesting thread: %s://%s%s", url.scheme().c_str(), url.host().c_str(), url.path().c_str());
		TaskThreadRequest* task = new TaskThreadRequest(threadId, url, tr("Requesting thread: %1").arg(threadId.threadNumericId()), requestManager());
		connect(task, SIGNAL(result(TaskThreadRequest*,QByteArray)), this, SLOT(slot_thread(TaskThreadRequest*,QByteArray)));
		TaskPtr taskptr = TaskPtr(task);
		m_taskhub->queueTask(taskptr);
	}

	void DefaultAgent::requestThumbnail(const PostId& postId, int attachmentIndex, const QUrl& thumblink)
	{
		QUrl link = thumblink;
		if(link.isRelative() || link.scheme().isEmpty())
			link.setScheme("http");
		if(link.host().isEmpty())
			link.setHost(m_host);

		log(llDebug, "DefaultAgent::requestThumbnail: %s", qPrintable(link.toString()));

		Wishmaster2::Network::Url url(link.toString().toStdString());

		TaskThumbnailRequest* task = new TaskThumbnailRequest(postId, attachmentIndex, url,
															  tr("Requesting thumbnail for post: ") + QString::number(postId.postId()), requestManager());
		connect(task, SIGNAL(result(TaskThumbnailRequest*,QByteArray)), this, SLOT(slot_thumb(TaskThumbnailRequest*,QByteArray)));
		TaskPtr taskptr = TaskPtr(task);
		m_taskhub->queueTask(taskptr);
	}

	void DefaultAgent::requestPic(const PostId& postId, int attachmentIndex, const QUrl& piclink)
	{
		Wishmaster2::Network::Url link(piclink.toString().toStdString());
		if(link.scheme().empty())
			link.setScheme("http");
		if(link.host().empty())
			link.setHost(m_host.toStdString());

		QString taskname;
		if(postId.postId() != 0)
			taskname = tr("Requesting picture for post: ") + QString::number(postId.postId());
		else
			taskname = tr("Requesting picture for thread: ") + QString::number(postId.threadId());
		TaskAttachmentRequest* task = new TaskAttachmentRequest(postId, attachmentIndex,
				link, taskname, requestManager());
		connect(task, SIGNAL(result(TaskAttachmentRequest*, QByteArray,QString)), this, SLOT(slot_pic(TaskAttachmentRequest*, QByteArray,QString)));
		TaskPtr taskptr = TaskPtr(task);

		QSettings settings;
		bool queuefirst = settings.value("connection/picRequestPriority", true).toBool();
		if(queuefirst)
		{
			m_taskhub->queueTaskFirst(taskptr);
		}
		else
		{
			m_taskhub->queueTask(taskptr);
		}

	}

	void DefaultAgent::downloadFile(const PostId& postId, int attachIndex, const QUrl& filelink, const QString& filename)
	{
		Wishmaster2::Network::Url link(filelink.toString().toStdString());
		if(link.scheme().empty())
			link.setScheme("http");
		if(link.host().empty())
			link.setHost(m_host.toStdString());

//		TaskRequest* task = new TaskRequest(PostId(postId.chan(), postId.board(), postId.threadId(), postId.postId()), attachIndex,
//				link, connector(), tr("Downloading file: ") + link.toString());
//		task->setProperty("filename", filename);
//		connect(task, SIGNAL(requestDone(int, PostId, QByteArray)), this, SLOT(slot_file(int, PostId, QByteArray)));
//		TaskPtr taskptr = TaskPtr(task);
//		m_taskhub->queueTask(taskptr);
	}

	void DefaultAgent::requestBoardIndex(const QString& boardId, int page)
	{
		Wishmaster2::Network::Url url;
		if(page == 0)
		{
			url = Wishmaster2::Network::Url((QString("http://") + makeFullHostname(boardId) + boardId).toStdString());
		}
		else
		{
			QString pageformat = m_pageformat;
			pageformat.replace("%BOARD%", boardId);
			pageformat.replace("%PAGE%", QString::number(page));
			url = Wishmaster2::Network::Url((QString("http://") + makeFullHostname(boardId) + pageformat).toStdString());
		}
		TaskBoardRequest* task = new TaskBoardRequest(m_host, boardId, url,
									 tr("Requesting board index: %1 (%2)").arg(boardId).arg(m_host),
									 requestManager());
		task->setProperty(PageProperty, page);

		log(llDebug, "DefaultAgent::requestBoardIndex");
		connect(task, SIGNAL(result(TaskBoardRequest*,QByteArray)), this, SLOT(slot_board(TaskBoardRequest*,QByteArray)));
		TaskPtr taskptr = TaskPtr(task);
		m_taskhub->queueTask(taskptr);
	}


	void DefaultAgent::slot_board(TaskBoardRequest* task, const QByteArray& arr)
	{
		int page = task->property(PageProperty).toUInt();

		log(llDebug, "DefaultAgent::slot_board: board index obtained");
		emit board(task->chanName(), task->boardId(), page, arr);
	}

	void DefaultAgent::slot_thread(TaskThreadRequest* task, const QByteArray& arr)
	{
		log(llDebug, "DefaultAgent::slot_thread: thread content obtained");
		emit thread(task->threadId(), arr);
	}

	void DefaultAgent::slot_thumb(TaskThumbnailRequest* task, const QByteArray& arr)
	{
		log(llDebug, "slot_thumb: %d", arr.size());
		emit thumb(task->postId(), task->attachmentIndex(), arr);
	}

	void DefaultAgent::slot_pic(TaskAttachmentRequest* task, const QByteArray& arr, const QString& contentType)
	{
		emit attachment(task->postId(), task->attachmentIndex(), arr, contentType);
	}

	
	void DefaultAgent::slot_file(int /*status*/, const PostId& postid, int attachmentIndex, const QByteArray& arr)
	{
		QFile f(sender()->property("filename").toString());
		f.open(QIODevice::WriteOnly);
		f.write(arr);
		f.close();
	}

	void DefaultAgent::slot_captchaFetcherResult(const ThreadId& threadid, const QByteArray& arr)
	{
		log(llDebug, "DefaultAgent::slot_captchaFetcherResult");
		emit captcha(threadid, arr);
	}

	void DefaultAgent::slot_mainpage(TaskRequest* task, const QByteArray& arr, const QString& contentType)
	{
		QString str = QString::fromUtf8(arr.data(), arr.length());
		QRegExp rx1("<link\\s+rel=\"(?:shortcut )?icon\"\\s+href=\"([^\\\"]*)\"[^>]*>");
		QRegExp rx2("<link\\s+href=\"([^\\\"]*)\"\\s+rel=\"(?:shortcut )?icon\"[^>]*>");

		QString favicon;

		if(rx1.indexIn(str) >= 0)
		{
			favicon = rx1.cap(1);
		}
		else if(rx2.indexIn(str))
		{
			favicon = rx2.cap(1);
		}

		if(favicon.isEmpty())
			favicon = "/favicon.ico";
		if(!favicon.startsWith("/"))
			favicon.prepend('/');

		Wishmaster2::Network::Url url(favicon.toStdString());
		if(url.host().empty() || url.scheme().empty())
		{
			url.setHost(makeFullHostname(QString()).toStdString());
			url.setScheme("http");
		}
		TaskRequest* newtask = new TaskRequest(TaskRequest::rtOther, url, tr("Requesting favicon (2)"), requestManager());

		connect(newtask, SIGNAL(result(TaskRequest*,QByteArray,QString)), this, SLOT(slot_favicon(TaskRequest*,QByteArray,QString)));
		TaskPtr taskptr = TaskPtr(newtask);
		m_taskhub->queueTask(taskptr);

		log(llDebug, "DefaultAgent::mainpage");

	}

	void DefaultAgent::slot_favicon(TaskRequest* task, const QByteArray& arr, const QString& contentType)
	{
		log(llDebug, "DefaultAgent::slot_favicon: %d/%s/%s", arr.size(), qPrintable(contentType), arr.data());
		emit favicon(m_host, arr);
	}

	QString DefaultAgent::makeFullHostname(const QString& board)
	{
		QString fullhost = m_host;
		if(property(QString("hostprefix" + board).toUtf8().data()).isValid())
			fullhost.prepend(property(QString("hostprefix" + board).toUtf8().data()).toString());
		return fullhost;
	}

	void DefaultAgent::deleteThread(const ThreadId& /*threadId*/, const QString& /*password*/)
	{
	}

	void DefaultAgent::deletePost(const PostId& /*postId*/, const QString& /*password*/)
	{
	}

	void DefaultAgent::addAttachments(Wishmaster2::Network::RequestPtr& r, const AttachmentDescriptor& attach, const QString& fieldname)
	{
		if(attach.filename.isEmpty())
		{
			r->addBinaryData(fieldname.toStdString(), "", std::vector<char>());
		}
		else
		{
			QFileInfo info(attach.filename);
			QByteArray data;
			if(attach.useData)
			{
				data = attach.data;
			}
			else
			{
				QFile file(attach.filename);
				if(file.open(QIODevice::ReadOnly))
				{
					data = file.readAll();
				}
			}
			if(data.isEmpty())
			{
				r->addBinaryData(fieldname.toStdString(), "", std::vector<char>());
			}
			else
			{
				foreach(const ExtraInfoDescriptor& extra, attach.extras)
				{
					data.append(extra.info);
				}
				std::vector<char> vecData(data.constData(), data.constData() + data.size());
				r->addBinaryData(fieldname.toStdString(), std::string(info.fileName().toUtf8().constData()), vecData);
			}
		}
	}

	ChanAgent* DefaultAgent::clone(const QString& host)
	{
		return new DefaultAgent(host);
	}

	QString DefaultAgent::id()
	{
		return "default";
	}
}

